﻿using System;
using System.Linq;

namespace Gabriel.Algoritimos
{
    public class Fila
    {
        #region Private Members

        private int _tamanho;
        private object[] _elementos;
        private int _count;
        private int _base;
        private int _topo;

        #endregion

        #region Public Members

        /// <summary>
        /// Indica quando a pilha esta cheia
        /// </summary>
        public bool Cheio { get { return Full(); } }
        /// <summary>
        /// Indica quando a pilha esta vazia
        /// </summary>
        public bool Vazio { get { return Empty(); } }
        /// <summary>
        /// Objecto que esta no topo da fila
        /// </summary>
        public object Topo { get { return RearObject(); } }
        /// <summary>
        /// Objeto que esta na base da pilha
        /// </summary>
        public object Base { get { return FrontObject(); } }
        /// <summary>
        /// Numero de objetos infileirados
        /// </summary>
        public int Count { get { return _count; } }
        /// <summary>
        /// Tamnho da fila
        /// </summary>
        public int Tamanho { get { return _tamanho; } }

        #endregion

        #region Public Methods

        /// <summary>
        /// Construtor 
        /// </summary>
        /// <param name="TamanhoMax">Tamanho maximo da fila</param>
        public Fila(int TamanhoMax)
        {
            _elementos = new object[TamanhoMax];
            _tamanho = TamanhoMax;
            _count = _base = 0;
            _topo = -1;
        }

        /// <summary>
        /// Retrona oque esta no base e o retira da pilha
        /// </summary>
        /// <returns>Objeto que estava no base da fila</returns>
        public object Remove()
        {
            if (Vazio) { throw new Exception("Pilha vazia"); }

            if (_base == _tamanho - 1) 
            { 
                _base = 0;
                _count--;
                return (_elementos[_tamanho - 1]);
            }
            else _base++;

            _count--;
            return (_elementos[_base-1]);
        }

        /// <summary>
        /// Insere um objeto na topo da fila
        /// </summary>
        /// <param name="elemento">Elemento que sera inserido no topo da pilha</param>
        public void Insere(object elemento)
        {
            
            if (Cheio) { throw new Exception("Pilha cheia"); }
            if (_topo == _tamanho -1) { _topo = 0; }
            else _topo++;

            _elementos[_topo] = elemento;
            _count++;
        }

        #endregion

        #region Private Methods

        private bool Full()
        {
            if (_tamanho == _count) { return true; }
            return false;   
        }

        private bool Empty()
        {
            if (_base == _tamanho) { return true; }
            return false; 
        }

        private object RearObject()
        {
            return _elementos[_topo];
        }

        private object FrontObject()
        {
            return _elementos[_base];
        }

        #endregion
    }
}
